/*
   Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
   Original sources are available at www.latestbit.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef BYTEARRAYINPUTOUTPUTSTREAM_HPP
#define BYTEARRAYINPUTOUTPUTSTREAM_HPP

#include "cpputils/CppUtils.hpp"
#include "cpputils/io/IInputStream.hpp"
#include "cpputils/io/IOutputStream.hpp"

namespace cpputils {
	namespace io {

		/**
		 * Implementation of piped I/O stream based on slices of byte arrays
		 * This implementation able to put ByteArray's and reading ByteArray's with the different lens.
		 * Block size per slice can be specified in the constructor when creation instance.
		 *
		 * @par Usage:
		 * @code
		 * // Creation a byte buffer with initial capacity 1024 bytes
		 * ByteBuffer* myBuffer = new ByteBuffer( 1024 );
		 *
		 * // Appending a C-style buffer
		 * const unsigned char cStyleBuffer[] =  { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
		 * myBuffer->append (cStyleBuffer, sizeof ( cStyleBuffer ) );
		 *
		 * // Creating stream
		 * ByteArrayInputOutputStream* stream = new ByteArrayInputOutputStream();
		 * // Write some data
		 * stream->write( myBuffer );
		 * // Read data into specified buffer
		 * ByteBuffer* outBuffer = new ByteBuffer( 512 );
		 * stream->read ( outBuffer );
		 * @endcode
		 */
		class ByteArrayInputOutputStream : public IInputStream, public IOutputStream {
		protected:
			unsigned int m_nBlockSize;
			typedef std::list < ByteBuffer::SharedPtr > Buffers;
			Buffers m_aBuffers;
			Buffers::iterator m_itCurrentWriteBuffer, m_itCurrentReadBuffer;
			unsigned int m_nCurrentWritePos, m_nCurrentReadPos;
			boost::mutex m_mxBuffers;

			bool m_bDumpMode;

			void createNewBuffer();
			void switchToNextWriteBuffer();
			void switchToNextReadBuffer();
			unsigned int writeBuffer(ByteBuffer* poBuffer, unsigned int nBytesRemaining );
			unsigned int m_nAllSize;

		public:
			CPPU_DLLPRFX ByteArrayInputOutputStream(unsigned int nBlockSize=4096);
			CPPU_DLLPRFX virtual ~ByteArrayInputOutputStream();
			CPPU_DLLPRFX virtual void write(ByteBuffer* poBuffer);
			CPPU_DLLPRFX virtual int read(ByteBuffer* poBuffer);
			CPPU_DLLPRFX void setDumpMode(bool bValue);
			CPPU_DLLPRFX void clear();
			CPPU_DLLPRFX bool empty();
			CPPU_DLLPRFX unsigned int size();

			typedef boost::shared_ptr <ByteArrayInputOutputStream> SharedPtr;
		};
	}
}

#endif // BYTEARRAYINPUTOUTPUTSTREAM_HPP
